#include "task_mqttHandle.h"

#include "tasksInit.h"
#include "task_cntlCenter.h"
#include "task_sensorData.h"

#include <stdio.h>
#include <string.h>

#include "los_task.h"
#include "los_queue.h"
#include "los_memory.h"
#include "los_event.h"

#include "cJSON.h"
#include "MQTTClient.h"

#include "bsp_e53.h"

#define MIN(a,b)        ( (a) < (b) ? (a) : (b))

// #define MQTT_MAX_RECV_LEN           128     //最大接收长度，128

#define MQTT_SERVER_IP              "192.168.1.116"
#define MQTT_SERVER_PORT            1883

unsigned int task_mqttHandle_id, task_mqttRecvCheck_id;
TSK_INIT_PARAM_S task_mqttHandle_handler = {
    (TSK_ENTRY_FUNC)task_mqttHandle,
    24,
    0,
    4096,
    "task_mqttHandle",
    0
};

static unsigned char mqtt_sendBuf[1024];
static unsigned char mqtt_readBuf[1024];

MQTTClient client;
MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer;
Network network;

void messageArrive_cb(MessageData* msg);
void cjson_init(void);

void task_mqttHandle(void)
{
    LOS_EventRead(&bspInit_ECB, BSPINIT_EVENT_INITOK, LOS_WAITMODE_AND, LOS_WAIT_FOREVER);

    printf("[mqtt handle] enter mqttHandle\n");

    //初始化cJSON

    //等待wifi初始化成功
    SetApModeOff();
    SetWifiModeOn();

    printf("[mqtt handle] Wifi Ready!\n");

    // 初始化MQTT
    int rc;
    
    // MQTTString clientId = MQTTString_initializer;

    printf("[mqtt handle] NetworkInit...\n");
    //1. 网络初始化
    NetworkInit(&network); 

begin:
    printf("[mqtt handle] NetworkConnect...\n");
    //2. 端口连接
    rc = NetworkConnect(&network, MQTT_SERVER_IP, MQTT_SERVER_PORT); 

    printf("[mqtt handle] MQTTClientInit...\n");
    //3. MQTTClient初始化
    MQTTClientInit(&client, &network, 2000, mqtt_sendBuf, sizeof(mqtt_sendBuf), mqtt_readBuf, sizeof(mqtt_readBuf));

    //设置连接参数
    connectData.clientID.cstring = "tqqjenid9kccitctih0y";
    // connectData.username.cstring = ;
    // connectData.password.cstring = ;
    connectData.willFlag = 0;
    connectData.MQTTVersion = 4; // 3: 3.1  4: 3.1.1
    connectData.keepAliveInterval = 60;
    connectData.cleansession = 1;

    printf("[mqtt handle] MQTTConnect...\n");
    //4. 正式连接
    rc = MQTTConnect(&client, &connectData);
    if(rc != 0){
        printf("[mqtt handle] MQTTConnect fail:%d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        LOS_Msleep(200);
        goto begin;
    }

    //5. 订阅主题
    printf("[mqtt handle] MQTTSubscribe...\n");
    rc = MQTTSubscribe(&client, "v1/devices/me/attributes", 1, messageArrive_cb);
    if(rc != 0){
        printf("[mqtt handle] MQTTSubscribe fail:%d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        LOS_Msleep(200);
        goto begin;
    }

    uint32_t ret = 0;
    sensor_data_t data;
    unsigned int data_len = sizeof(data);

    MQTTMessage message;

    //cJSON初始化
    cjson_init();

    cJSON *root = NULL;
    char* data_string = NULL;

    while(1)
    {
        //1. 读数据队列
        ret = LOS_QueueReadCopy(sensorData_qId, &data, &data_len, LOS_WAIT_FOREVER);
        if(ret != LOS_OK)
        {
            printf("LOS_QueueReadCopy error, ret=0x%x.\n", ret);
            continue;
        }

        //2. 转换json, 填message
        root = cJSON_CreateObject();
        //添加json结点
        cJSON_AddNumberToObject(root, "humidity", data.humidity);
        cJSON_AddNumberToObject(root, "luminance", data.lumi_lux);
        cJSON_AddNumberToObject(root, "temperature", data.tempe_c);
        cJSON_AddNumberToObject(root, "MQ2_smokeScope", data.mq2_ppm);

        data_string = cJSON_PrintUnformatted(root);     //会自动申请空间
        // printf("[mqtt handle] data_string:%s\n", data_string);

        cJSON_Delete(root);

        message.qos = 1;
        message.retained = 0;
        message.payload = data_string;
        message.payloadlen = strlen(message.payload);

        //3. 发送数据
        rc = MQTTPublish(&client, "v1/devices/me/telemetry", &message);
        if(rc != 0)
        {
            printf("Return code from MQTT publish is %d\n", rc);
            NetworkDisconnect(&network);
            MQTTDisconnect(&client);
            goto begin;
        }

        LOS_MemFree(OS_SYS_MEM_ADDR, (void *)data_string);  //释放空间
        
        LOS_Msleep(1000);
    }
}

// char recv_msg_string[MQTT_MAX_RECV_LEN];
cntl_msg_t cntl_msg;
void messageArrive_cb(MessageData* msg)
{
    //填消息队列
    cJSON *root = NULL, *cur_elem = NULL;
    // char* name = NULL;
    int name_size = 0;
    // void* param = NULL;

    root = cJSON_Parse(msg->message->payload); //初始化
    if(root == NULL)
    {
        printf("[messageArrive_cb] cJSON_Parse() error, root is NULL!\n");
        return ;
    }

    cJSON_ArrayForEach(cur_elem, root)
    {
        cntl_msg.source = CNTL_MSG_SOURCE_FROM_MQTT;
        cntl_msg.type = CNTL_MSG_TYPE_NAME;

        //copy name
        name_size = MIN(strlen(cur_elem->string)+1, MAX_NAME_SIZE);//包括结束符
        cntl_msg.name = LOS_MemAlloc(OS_SYS_MEM_ADDR, name_size);
        snprintf(cntl_msg.name, name_size, "%s", cur_elem->string);

        //namestring
        if(cJSON_IsBool(cur_elem))
        {
            cntl_msg.param = LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(int));
            if(cJSON_IsTrue(cur_elem))
            {
                *(int *)(cntl_msg.param) = 1;
            }
            else
            {
                *(int *)(cntl_msg.param) = 0;
            }
        }
        else if(cJSON_IsNumber(cur_elem))
        {
            cntl_msg.param = LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(int));
            *(int *)(cntl_msg.param) = (int)cur_elem->valuedouble;
        }
        // ...

        //填队列
        LOS_QueueWriteCopy(cntlCenter_qId, (void *)&cntl_msg, sizeof(cntl_msg), 1);
        //test
        // printf("[messageArrive_cb] cntl_msg->name:%s, cntl_msg->value:%d", cntl_msg.name, *(int *)(cntl_msg.param));
    }

    // printf("[messageArrive_cb] message arrived on topic %.*s: %.*s\n", msg->topicName->lenstring.len, msg->topicName->lenstring.data,
    //     msg->message->payloadlen, msg->message->payload);

}

void* my_malloc(size_t sz)
{
    return LOS_MemAlloc(OS_SYS_MEM_ADDR, sz);
}

void my_free(void *ptr)
{
    LOS_MemFree(OS_SYS_MEM_ADDR, ptr);
}

void cjson_init(void)
{
    cJSON_Hooks hooks;
    hooks.malloc_fn = my_malloc;
    hooks.free_fn = my_free;
    cJSON_InitHooks(&hooks);
}
